{# Context schema:
  * cytoscape_url: string. The path to the Cytoscape library.
  * dagre_url: string. The path to the Dagre library.
  * cytoscape_dagre_url: string. The path to the cytoscape-dagre library.
  * program: string. The JSON encoding of a pytype.typegraph.cfg.Program. Should
    be created by typegraph_serializer.encode_program.
  * var_table: dict[int, str]. A mapping of Variable IDs to names.
  * query_table: list[typegraph_serializer.SerializedQuery]. A list of query
    descriptions, created by the typegraph serializer.
#}
<!doctype html>

<html>

<head>
    <title>Pytype CFG Visualizer</title>
    <script src="{{cytoscape_url}}"></script>
    <script src="{{dagre_url}}"></script>
    <script src="{{cytoscape_dagre_url}}"></script>
</head>

<style>
    #cy {
        width: 100%;
        height: 100%;
        position: absolute;
        top: 0px;
        left: 0px;
        z-index: -1;
    }

    #variables-div {
        max-width: 10%;
        max-height: 30%;
        position: absolute;
        top: 0px;
        left: 0px;
        z-index: 1;
        margin: 2px 5px;
        background: #fff;
    }

    #variables-table {
        overflow: auto;
    }

    #query-div {
        max-width: 25%;
        max-height: 30%;
        display: flex;
        flex-flow: column;
        position: absolute;
        top: 0px;
        right: 0px;
        z-index: 1;
        margin: 2px 5px;
        background: #fff;
    }

    #query-header {
      display: flex;
      flex: initial;
      flex-flow: row nowrap;
      align-items: center;
    }

    #query-title {
        display: flex;
        flex: auto;
        font-style: bold;
    }

    .query-button {
      display: flex;
      flex: initial;
      margin: 3px 5px;
    }

    #query-table {
        flex: 1 25%;
        overflow: auto;
    }

    #legend-cy {
      width: 550px;
      height: 225px;
      position: absolute;
      left: 0px;
      bottom: 0px;
      margin: 2px 5px;
      border-style: solid;
      background: #fff;
    }

    #legend-title {
      width: 100%;
      position: absolute;
      top: -25;
      text-align: center;
      font-size: large;
    }

    tr.datarow:hover {
      background-color: lightsteelblue;
    }

    tr.datarow.selected-row {
      background-color: lightsteelblue;
    }

    table, th, td {
      border: 1px solid;
      border-collapse: collapse;
    }

    td {
      padding: 2px 4px;
    }
</style>

<body>
    <div id="variables-div">
      <div id="variables-title">Variables</div>
      <div id="table-div">
        <table id="variables-table">
          <tr>
            <th>ID</th>
            <th>Name</th>
          </tr>
          {%- for (vid, name) in var_table|dictsort %}
          <tr class=datarow onclick="vis.add_or_hide_var({{vid}})" onmouseover="vis.highlight_var({{vid}})" onmouseout="vis.unhighlight_var({{vid}})">
            <td>{{vid}}</td>
            <td>{{name}}</td>
          </tr>
          {%- endfor %}{# var_table #}
        </table>
      </div>
    </div>
    <div id="query-div">
      <div id="query-header">
        <div id="query-title">Queries</div>
        <button class="query-button" type="button" onclick="vis.retreat_query()">Prev Step</button>
        <button class="query-button" type="button" onclick="vis.advance_query()">Next Step</button>
      </div>
      <div id="table-div">
        <table id="query-table">
          <tr>
            <th>S#</th> <!-- Solver # -->
            <th>Cached?</th> <!-- From Cache? -->
            <th>Shortcircuited?</th> <!-- Shortcircuited? -->
            <th>Start Node</th> <!-- Starting Node -->
            <th>Description</th> <!-- Query Description -->
          </tr>
          {%- for query in query_table %}
          <tr id="query_row{{loop.index0}}" class=datarow onclick="select_query({{loop.index0}})" onmouseover="vis.highlight_cfgnode({{query.start_node}})" onmouseout="vis.unhighlight_cfgnode({{query.start_node}})">
            <td>{{query.solver_idx}}</td>
            <td>{{query.from_cache}}</td>
            <td>{{query.shortcircuited}}</td>
            <td>{{query.start_node}}</td>
            <td>{{query.initial_binding_count}} binding(s)</td>
          </tr>
          {%- endfor %}{# queries #}
        </table>
      </div>
    </div>
    <div id="cy"></div>
    <div id="legend-cy">
      <div id="legend-title">Legend</div>
    </div>
    <script>
      const layout_options = {
        name: 'dagre',
        nodeDimensionsIncludeLabels: true,
        nodeSep: 1,
      };
      const style = [
        // All graph nodes have their text centered by default. They are
        // labeled using their name, with black text with a white outline.
        {
          selector: 'node',
          style: {
            'label': 'data(name)',
            'text-halign': 'center',
            'text-valign': 'center',
            'text-outline-color': '#fff',
            'text-outline-width': 2,
          },
        },
        {
          selector: '.cfg_node',
          style: {
            'shape': 'ellipse',
          },
        },
        {
          selector: '.variable_node',
          style: {
            'shape': 'rectangle',
          },
        },
        {
          selector: '.binding_node',
          style: {
            'shape': 'diamond',
          },
        },
        {
          selector: '.sourceset_node',
          style: {
            'shape': 'round-octagon',
          },
        },
        // All edges have the 'bezier' curve style, which works for multiple
        // edges between the two nodes and enables all arrow shapes.
        {
          selector: 'edge',
          style: {
            'curve-style': 'bezier',
          },
        },
        {# edge from CFG Node to CFG Node #}
        {
          selector: '.cfgnode_edge',
          style: {
            'line-color': '#000',
            'width': 4,
            'target-arrow-color': '#f00',
            'target-arrow-shape': 'triangle',
          },
        },
        {# edge from Variable to Binding. #}
        {
          selector: '.var_bind_edge',
          style: {
            'line-color': 'pink',
            'width': 3,
            'source-arrow-color': 'red',
            'source-arrow-shape': 'diamond',
            'target-arrow-color': 'red',
            'target-arrow-shape': 'diamond',
          },
        },
        {# edge from SourceSet to CFG Node #}
        {
          selector: '.source_cfgnode_edge',
          style: {
            'line-color': 'black',
            'width': 2,
            'line-style': 'dotted',
          },
        },
        {# edge from Binding to origin SourceSet #}
        {
          selector: '.bind_source_edge',
          style: {
            'line-color': 'black',
            'width': 3,
          },
        },
        {# edge from SourceSet to member Binding #}
        {
          selector: '.source_member_edge',
          style: {
            'line-color': 'blue',
            'width': 2,
            'source-arrow-color': 'blue',
            'source-arrow-shape': 'square',
            'target-arrow-color': 'blue',
            'target-arrow-shape': 'square',
          },
        },
        {# edge from CFGNode to Binding #}
        {
          selector: '.cfgnode_bind_edge',
          style: {
            'width': 2,
            'source-arrow-shape': 'diamond',
            'target-arrow-shape': 'diamond',
          },
        },
        {# Used for animating nodes that appear #}
        {
          selector: '.highlight_node',
          style: {
            'border-color': 'blue',
            'border-width': 3,
            'line-color': 'blue',
          },
        },
        {# This style is last so that it matches every node with the "hidden_node" class. #}
        {
          selector: '.hidden_node',
          style: {
            'display': 'none',
          },
        },
      ];
      const cy = cytoscape({
        container: document.getElementById('cy'),
        data: {
          layout_options: layout_options,
        },
        elements: [],
        style: style,
      });

      {% include "visualizer.js" %}
      const program = {{program}};

      const vis = new Visualizer(cy, program);

      const legend_cy = cytoscape({
        container: document.getElementById('legend-cy'),
        data: {
          layout_options: {
            ...layout_options
          }
        },
        elements: vis.gen_legend(),
        style: style,
        {# these options make the legend non-interactive. #}
        autoLock: true,
        autoungrabify: true,
        autounselectify: true,
        userZoomingEnabled: false,
        userPanningEnabled: false,
        boxSelectionEnabled: false,
      });
      legend_cy.layout(legend_cy.data('layout_options')).run();
    </script>
</body>
</html>
{# end of template #}
